
#ifndef _SEM_LOCK_H_
#define _SEM_LOCK_H_

#include <semaphore.h>

namespace trident {

/**
 * thread semaphore lock
 */
class sem_lock_t
{
public:
    /**
     * constructor
     */
	sem_lock_t(unsigned int value_ = 0)
    {
        if (::sem_init(&_sem, 0, value_))
        {
           //EMPTY
        }
    }

    /**
     * destructor
     */
	~sem_lock_t()
    {
        if (::sem_destroy(&_sem))
        {
           //EMPTY
        }
    }

    /**
     * increment semaphore
     * @return 0: successful
     * @return -1: error and check the errno
     */
	int post()
    {
        return ::sem_post(&_sem);
    }

    /**
     * wait semaphore and will be blocked
     * @return 0: successful
     * @return -1: error and check the errno
     */
	void wait()
    {
        ::sem_wait(&_sem);
    }

    /**
     * wait semaphore and return immediately
     * @return 0: successful
     * @return -1: error and check the errno
     */
	int tryWait()
    {
        return ::sem_trywait(&_sem);
    }

    /**
     * wait semaphore for special seconds
     * int interval_: timeout seconds
     * @return ETIMEDOUT: return timeout
     * @return 0: successful
     * @return -1: error and check the errno
     * 
     */
    int timeWait(int timeout_)
    {
        timespec ts;
        ts.tv_sec = ::time(NULL) + timeout_;
        ts.tv_nsec = 0;

        // if sem_timedwait return -1, the function return errno
        // ETIMEDOUT: for timer out
        return sem_timedwait(&_sem, &ts) ? errno : 0;
    }

    /**
     * get the semaphore value
     */
	int getValue()
	{
		int value = 0;
		::sem_getvalue(&_sem, &value);

		return value;
	}

private:
	sem_t	            _sem;

    // forbidden copy and assign construct
    sem_lock_t(const sem_lock_t&);
    sem_lock_t& operator=(const sem_lock_t&);
};

} // namespace trident

#endif //_SEM_LOCK_H_
